package com.aboverock.module.system.web;

import com.aboverock.autoconfigure.util.JwtUtil;
import com.aboverock.common.domain.Result;
import com.aboverock.common.enums.UserTypeEnum;
import com.aboverock.core.exception.CustomAuthenticationException;
import com.aboverock.core.exception.CustomLockedAccountException;
import com.aboverock.core.token.LdapUserLoginToken;
import com.aboverock.core.token.LocalUserLoginToken;
import com.aboverock.core.token.TokenLoginToken;
import com.aboverock.module.shiro.util.ShiroCacheUtil;
import com.aboverock.module.system.domain.LoginUser;
import com.aboverock.module.system.utils.UserInfoUtil;
import io.jsonwebtoken.Claims;
import io.swagger.annotations.ApiOperation;
import java.util.HashMap;
import java.util.Map;
import javax.validation.Valid;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * 登录登出类.
 *
 * @author Rock Wang
 */
@RestController
@RequestMapping("/sys")
public class LoginController {

    @ApiOperation(value = "用户登录，若未指定登录用户类型，则默认为AD域帐号")
    @PostMapping("/login")
    public Result login(@Valid @RequestBody LoginUser user)
            throws CustomLockedAccountException, CustomAuthenticationException {
        UsernamePasswordToken token;
        if (UserInfoUtil.isSuperAdminName(user.getLoginName())) {
            token = new LocalUserLoginToken(user.getLoginName(), user.getPassword());
        } else if(UserTypeEnum.AD.getValue() == user.getType()) {
            token = new LdapUserLoginToken(user.getLoginName(), user.getPassword());
        } else {
            user.setLoginName(UserInfoUtil.addSuffix2LocalUserLoginName(user.getLoginName()));
            token = new LocalUserLoginToken(user.getLoginName(), user.getPassword());
        }

        try {
            SecurityUtils.getSubject().login(token);
        } catch (LockedAccountException e) {
            throw new CustomLockedAccountException(e);
        } catch (AuthenticationException e) {
            throw new CustomAuthenticationException(e);
        }

        String loginName = user.getLoginName().toLowerCase();
        Map<String, Object> params = new HashMap<>(1);
        String jwtToken = JwtUtil.generateToken(loginName);
        params.put(JwtUtil.getHeader(), jwtToken);

        // 登录成功后生成JWT，存入缓存中
        ShiroCacheUtil.getAuthecticationCache().put(loginName, jwtToken);

        return Result.success(params);
    }

    @ApiOperation(value = "用户退出")
    @PostMapping("/logout")
    public Result logout() {
        SecurityUtils.getSubject().logout();
        String loginName = JwtUtil.getLoginName();
        // 清除当前用户的JWT缓存
        ShiroCacheUtil.removeAuthecticationInfo(loginName);
        // 清除当前用户的权限缓存
        ShiroCacheUtil.removeAuthorizationInfo(loginName);

        return Result.success();
    }

    @ApiOperation(value = "使用token登录另一系统")
    @PostMapping("/tokenLogin")
    public Result tokenLogin(@RequestParam String token)
            throws CustomLockedAccountException, CustomAuthenticationException {
        TokenLoginToken jwtLoginToken = new TokenLoginToken(token);

        try {
            SecurityUtils.getSubject().login(jwtLoginToken);
        } catch (LockedAccountException e) {
            throw new CustomLockedAccountException(e);
        } catch (AuthenticationException e) {
            throw new CustomAuthenticationException(e);
        }

        Claims claims = JwtUtil.getClaimByToken(token);
        String loginName = claims.getSubject();
        Map<String, Object> params = new HashMap<>(1);
        params.put(JwtUtil.getHeader(), token);

        // 登录成功后生成JWT，存入缓存中
        ShiroCacheUtil.getAuthecticationCache().put(loginName, token);

        return Result.success(params);
    }

}
